package com.usefullc.system.service.component.extend;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.usefullc.common.constants.SystemConstant;
import com.usefullc.common.domain.BaseDomain;
import com.usefullc.common.util.CookieUtil;
import com.usefullc.common.util.NumberUtil;
import com.usefullc.common.util.RequestUtils;
import com.usefullc.common.util.http.HttpNewUtils;
import com.usefullc.common.util.http.RequestRes;
import com.usefullc.common.util.http.ResponseRes;
import com.usefullc.system.entity.Pager;
import com.usefullc.system.entity.WebResult;
import com.usefullc.system.service.AbstractService;
import com.usefullc.common.util.JsonUtil;
import com.usefullc.system.domain.DataDict;
import com.usefullc.system.service.CommonService;
import com.usefullc.system.service.DataDictService;
import com.usefullc.system.service.component.SystemConfigComponent;
import com.usefullc.system.vo.DataOptionVo;
import com.usefullc.system.vo.OptionVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 扩展数据处理组件
 *
 * @author: Sampson
 * @date: 2022-06-19 15:31
 */
@Component
public class ExtendDataComponent extends AbstractService {

    @Value("${usefullc.api.host}")
    private String apiHost;

    @Value("${usefullc.extendDetail}")
    private Boolean extendDetail;

    @Autowired
    private RedisTemplate redisTemplate;


//    @Autowired
//    private ImgCodeComponent imgCodeComponent;

    @Autowired
    private SystemConfigComponent systemConfigComponent;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private DataDictService dataDictService;

    @Autowired
    private CommonService commonService;

    public WebResult wrapperWebResult(WebResult webResult) {
        Object data = webResult.getData();
        if (data == null) {
            return webResult;
        }
        data = wrapperData(data);
        webResult.setData(data);
        return webResult;
    }

    public Object wrapperData(Object data) {
        //对象子集扫描最大深度
        int maxDepth = 5;
        //是否返回字典
        HttpServletRequest request = RequestUtils.getRequest();
        String showDictText = request.getParameter(SystemConstant.EXTEND_DETAIL);
        if (StringUtils.isNotEmpty(showDictText)) {
            extendDetail = BooleanUtils.toBoolean(showDictText);
        }
        if (!extendDetail) {
            return data;
        }

        try {
            if (data instanceof Pager) {
                Pager pager = (Pager) data;
                List dataList = pager.getDataList();
                List<JSONObject> jsonObjects = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(dataList)) {
                    for (Object obj : dataList) {
                        if (!(obj instanceof BaseDomain)) {
                            return data;
                        }
                        jsonObjects.add(wrapperObject(obj, maxDepth));
                    }
                }
                pager.setDataList(jsonObjects);

            } else if (data instanceof ArrayList) {
                List dataList = (List) data;
                List<JSONObject> jsonObjects = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(dataList)) {
                    for (Object obj : dataList) {
                        if (!(obj instanceof BaseDomain)) {
                            return data;
                        }
                        jsonObjects.add(wrapperObject(obj, maxDepth));
                    }
                }
                data = dataList;
            } else if (data instanceof BaseDomain) {
                JSONObject jsonObject = wrapperObject(data, maxDepth);
                data = jsonObject;
            }
        } catch (Exception e) {
            logger.error("error", e);
        }
        return data;

    }

    private JSONObject wrapperObject(Object obj, int depth) {
        depth--;
        String json = JsonUtil.bean2Json(obj);
        JSONObject jsonObject = JsonUtil.json2Bean(json, JSONObject.class);
        if (depth <= 0) {
            return jsonObject;
        }
        Field[] declaredFields = FieldUtils.getAllFields(obj.getClass());
        for (int i = 0; i < declaredFields.length; i++) {
            Field field = declaredFields[i];
            if (StringUtils.equalsIgnoreCase(field.getName(), "serialVersionUID")) {
                continue;
            }
            try {
                field.setAccessible(true);
                Object fieldValue = field.get(obj);
                field.setAccessible(false);
                if (fieldValue == null) {
                    continue;
                }
                if (fieldValue instanceof BaseDomain) {  //子对象
                    JSONObject childJsonObj = wrapperObject(fieldValue, depth);
                    jsonObject.put(field.getName(), childJsonObj);
                } else if (fieldValue instanceof List) {
                    List childDataList = (List) fieldValue;
                    List<JSONObject> jsonObjects = new ArrayList<>();
                    if (childDataList.size() > 0 && childDataList.get(0) instanceof BaseDomain) {
                        for (Object childObj : childDataList) {
                            JSONObject childListJsonObj = wrapperObject(childObj, depth);
                            jsonObjects.add(childListJsonObj);
                        }
                        jsonObject.put(field.getName(), jsonObjects);
                    }
                } else {
                    DictField annotation = field.getAnnotation(DictField.class);
                    if (annotation != null) {
                        String value = annotation.value();
                        //先获取父级
                        DataDict parentDataDict = dataDictService.getParentByValue(value);
                        String code = parentDataDict.getCode();
                        DataDict dataDict = dataDictService.getCodeLikeAndValue(code, fieldValue.toString());
                        jsonObject.put(field.getName() + "Dict", dataDict);
                    } else {
                        EnumField enumField = field.getAnnotation(EnumField.class);
                        if (enumField != null) {
                            String value = enumField.value();
                            DataOptionVo dataOptionVo = commonService.getByEnumName(value);
                            if(dataOptionVo == null){
                                logger.warn("field not Enum,filed={}",field);
                                continue;
                            }
                            List<OptionVo> optionList = dataOptionVo.getOptionList();
                            for (OptionVo optionVo : optionList) {
                                if (fieldValue instanceof String) {
                                    if (StringUtils.equalsIgnoreCase(optionVo.getValue().toString(), fieldValue.toString())) {
                                        jsonObject.put(field.getName() + "Enum", optionVo);
                                        break;
                                    }
                                } else {
                                    if (Integer.valueOf(optionVo.getValue().toString()).intValue() == Integer.valueOf(fieldValue.toString())) {
                                        jsonObject.put(field.getName() + "Enum", optionVo);
                                        break;
                                    }
                                }
                            }

                        }

                    }

                    ApiField apiField = field.getAnnotation(ApiField.class);
                    if (apiField != null) {
                        try {
                            String url = apiField.url();
                            String id = apiField.id();
//                            String value = apiField.value();
                            if (!url.startsWith("http")) {
                                url = apiHost + url;
                            }
                            RequestRes requestRes = new RequestRes();
                            HttpServletRequest request = RequestUtils.getRequest();
                            requestRes.setUrl(url);
                            requestRes.setMethod("GET");
                            String token = request.getHeader("token");
                            if (StringUtils.isEmpty(token)) {
                                token = CookieUtil.getCookieValue(RequestUtils.getRequest(),"token");
                            }
                            requestRes.addHeader("token", token);

//                            String paramJson = "{" + id + ":" + fieldValue + "}";
                            if (!url.endsWith("listTree")) {
//                                Map<String, Object> param = new HashMap<>();
//                                param.put(id,fieldValue);
//                                requestRes.setParams(param);
                                url = url + "?"+id+"="+fieldValue.toString();
                                requestRes.setUrl(url);
//                                requestRes.setParamText(paramJson);
                            }
                            ResponseRes responseRes = HttpNewUtils.execute(requestRes);
                            String bodyText = responseRes.getBodyText();
                            WebResult webResult = JsonUtil.json2Bean(bodyText, WebResult.class);

                            List dataList = (List) webResult.getData();
                            if (!url.endsWith("listTree")) {
                                if (CollectionUtils.isNotEmpty(dataList)) {
                                    Object object = dataList.get(0);
                                    jsonObject.put(field.getName() + "Api", object);
                                }
                            } else {
                                //遍历树
                                boolean find = false;
                                for (Object object : dataList) {
                                    if (find) {
                                        break;
                                    }
                                    JSONObject jo = (JSONObject) object;
                                    JSONArray children = jo.getJSONArray("children");
                                    if (children == null) {
                                        continue;
                                    }
                                    for (int cIndex = 0; cIndex < children.size(); cIndex++) {
                                        JSONObject childrenJsonObj = children.getJSONObject(cIndex);
                                        Object val = childrenJsonObj.get(id);
                                        if (StringUtils.equalsIgnoreCase(val.toString(), fieldValue.toString())) {
                                            jsonObject.put(field.getName() + "Api", childrenJsonObj);
                                            break;
                                        }
                                    }

                                }
                            }
//                            if (object != null) {
//                                Field valField = FieldUtils.getField(object.getClass(), value, true);
//                                Object val = valField.get(object);
//                                if (val instanceof String) {
//                                    if (StringUtils.equalsIgnoreCase(val.toString(), fieldValue.toString())) {
//                                        break;
//                                    }
//                                } else {
//                                    if (Integer.valueOf(val.toString()).intValue() == Integer.valueOf(fieldValue.toString())) {
//                                        jsonObject.put(field.getName() + "Api", object);
//                                        break;
//                                    }
//                                }
//                            }
                        } catch (Exception e) {
                            logger.error("apiField error", e);
                        }
                    }
                    Object newFieldValue = null;
                    UsefulField usefulField = field.getAnnotation(UsefulField.class);
                    if (usefulField != null) {
                        String format = usefulField.format();
                        if (StringUtils.isNotEmpty(format)) {
                            if (fieldValue instanceof Date) {
                                newFieldValue = DateFormatUtils.format((Date) fieldValue, format);
                            } else if (fieldValue instanceof Integer) {  //todo
                            }
                        }
                        Class cls = usefulField.convertType();
                        String name = cls.getName();
                        switch (name) {
                            case "java.lang.String":
                                newFieldValue = String.valueOf(fieldValue);
                                break;
                            case "java.lang.Integer":
                                newFieldValue =  NumberUtil.toInt(fieldValue.toString());
                                break;
                            case "java.lang.Byte":
                                newFieldValue = Byte.parseByte(fieldValue.toString());
                                break;
                            case "java.lang.Boolean":
                                newFieldValue = Boolean.parseBoolean(fieldValue.toString());
                                break;
                            case "java.lang.Double":
                                newFieldValue = Double.parseDouble(fieldValue.toString());
                                break;
                            case "java.lang.Float":
                                newFieldValue = Float.parseFloat(fieldValue.toString());
                                break;
                            case "java.lang.Long":
                                newFieldValue = Long.parseLong(fieldValue.toString());
                                break;
                            case "java.lang.Short":
                                newFieldValue = Short.parseShort(fieldValue.toString());
                                break;
                        }
                        jsonObject.put(field.getName(), newFieldValue);
                    }
                }


            } catch (Exception e) {
                logger.error("error", e);
            }
        }
        return jsonObject;
    }


}
